package cn.xiaolang.function.retrying;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;

import com.github.rholder.retry.RetryException;
import com.github.rholder.retry.Retryer;
import com.github.rholder.retry.RetryerBuilder;
import com.github.rholder.retry.StopStrategies;
import com.github.rholder.retry.WaitStrategies;
import com.google.common.base.Predicate;

/**
 * Guava retryer工具与spring-retry类似，都是通过定义重试者角色来包装正常逻辑重试，但是Guava
 * retryer有更优的策略定义，在支持重试次数和重试频度控制基础上，能够兼容支持多个异常或者自定义实体对象的重试源定义，让重试功能有更多的灵活性。Guava
 * Retryer也是线程安全的，入口调用逻辑采用的是Java.util.concurrent.Callable的call方法
 * 
 * @author DeanKano
 * @date 2018年3月15日
 */
public class GuavaRetryDemo {

	public static void main(String[] args) {
		retryHandler(-1);
	}

	private static void retryHandler(final long id) {
		RetryerBuilder<Boolean> newBuilder = RetryerBuilder.newBuilder();
		Retryer<Boolean> retryer = newBuilder.retryIfException()
				.retryIfResult(new Predicate<Boolean>() {// 设置自定义段元重试源，
			@Override
			public boolean apply(Boolean state) {// 特别注意：这个apply返回true说明需要重试，与操作逻辑的语义要区分
				return state;
			}
		}).withStopStrategy(StopStrategies.stopAfterAttempt(3))// 设置重试3次，同样可以设置重试超时时间
				.withWaitStrategy(WaitStrategies.fixedWait(100L, TimeUnit.MILLISECONDS)).build();// 设置每次重试间隔

		try {
			// 重试入口采用call方法，用的是java.util.concurrent.Callable<V>的call方法,所以执行是线程安全的
			retryer.call(new Callable<Boolean>() {
				@Override
				public Boolean call() throws Exception {
					try {
						// 特别注意：返回false说明无需重试，返回true说明需要继续重试
						System.out.println("retry");
						return getName(id);
					} catch (Exception e) {
						throw new Exception(e);
					}
				}
			});

		} catch (ExecutionException e) {
		} catch (RetryException ex) {
		}
	}

	public static boolean getName(long id) {
		if (id < 0) {
			System.err.println("重试：" + id);
			return true;
		} else {
			System.err.println("xl:" + id);
			return false;
		}
	}

}
